package com.xa.xamall.framework.service;

import com.github.pagehelper.PageHelper;

import com.xa.xamall.framework.mapper.MyMapper;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.entity.Example;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.util.List;

/**
 * 泛型仓储接口实现类
 * @param <T> 实体对象
 */
public class BaseService<T> implements IBaseService<T> {

    /**
     * 自定义继承所有接口
     */
    @Autowired
    protected MyMapper<T> myMapper;

    /**
     * 根据实体中的属性值进行查询，查询条件使用等号
     * 接口：SelectMapper<T>
     * @param record 数据记录
     * @return List<T>
     */
    @Override
    public List<T> select(T record) {
        return myMapper.select(record);
    }

    /**
     * 根据主键字段进行查询，方法参数必须包含完整的主键属性，查询条件使用等号
     * 接口：SelectByPrimaryKeyMapper<T>
     * @param key 主键
     * @return T
     */
    @Override
    public T selectByPrimaryKey(Object key) {
        return myMapper.selectByPrimaryKey(key);
    }

    /**
     * 查询全部结果，select(null)方法能达到同样的效果
     * 接口：SelectAllMapper<T>
     * @return List<T>
     */
    @Override
    public List<T> selectAll() {
        return myMapper.selectAll();
    }

    /**
     * 查询分页结果
     * 接口：SelectAllMapper<T>
     * @param example 查询条件
     * @return List<T>
     */
    @Override
    public List<T> selectAll(Example example) {
        return myMapper.selectByExample(example);
    }

    /**
     * 查询分页结果
     * 接口：SelectAllMapper<T>
     * @param currPage 当前页码
     * @param pageSize 分页大小
     * @return List<T>
     */
    @Override
    public List<T> selectAll(int currPage, int pageSize) {
        PageHelper.startPage(currPage, pageSize);
        return myMapper.selectAll();
    }

    /**
     * 查询分页结果
     * 接口：SelectAllMapper<T>
     * @param example 查询条件
     * @param currPage 当前页码
     * @param pageSize 分页大小
     * @return List<T>
     */
    @Override
    public List<T> selectAll(Example example, int currPage, int pageSize) {
        PageHelper.startPage(currPage, pageSize);
        return myMapper.selectByExample(example);
    }

    /**
     * 根据实体中的属性进行查询，只能有一个返回值，有多个结果则抛出异常，查询条件使用等号
     * 接口：SelectOneMapper<T>
     * @param record 数据记录
     * @return T
     */
    @Override
    public T selectOne(T record) {
        return myMapper.selectOne(record);
    }

    /**
     * 根据属性进行查询，只能有一个返回值，有多个结果则抛出异常，查询条件使用等号
     * 接口：SelectOneMapper<T>
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return T
     */
    @Override
    public T selectOneByField(String fieldName, Object fieldValue) {
        Class<T> tClass = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        T example = null;
        try {
            example = tClass.newInstance();
            BeanUtils.setProperty(example, fieldName, fieldValue);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return myMapper.selectOne(example);
    }

    /**
     * 根据实体中的属性查询总数，查询条件使用等号
     * 接口：SelectCountMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    @Override
    public int selectCount(T record) {
        return myMapper.selectCount(record);
    }

    /**
     * 保存一个实体，null的属性也会保存，不会使用数据库默认值
     * 接口：InsertMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    @Override
    public int insert(T record) {
        return myMapper.insert(record);
    }

    /**
     * 保存一个实体，null的属性不会保存，会使用数据库默认值
     * 接口：InsertSelectiveMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    @Override
    public int insertSelective(T record) {
        return myMapper.insertSelective(record);
    }

    /**
     * 根据主键更新实体全部字段，null值会被更新
     * 接口：UpdateByPrimaryKeyMapper<T>
     * @param record
     * @return 受影响的行数
     */
    @Override
    public int updateByPrimaryKey(T record) {
        return myMapper.updateByPrimaryKey(record);
    }

    /**
     * 根据主键更新属性不为null的值
     * 接口：UpdateByPrimaryKeySelectiveMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    @Override
    public int updateByPrimaryKeySelective(T record) {
        return myMapper.updateByPrimaryKeySelective(record);
    }

    /**
     * 根据实体属性作为条件进行删除，查询条件使用等号
     * 接口：DeleteMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    @Override
    public int delete(T record) {
        return myMapper.delete(record);
    }

    /**
     * 根据主键字段进行删除，方法参数必须包含完整的主键属性
     * 接口：DeleteByPrimaryKeyMapper<T>
     * @param key 主键
     * @return 受影响的行数
     */
    @Override
    public int deleteByPrimaryKey(Object key) {
        return myMapper.deleteByPrimaryKey(key);
    }

    /**
     * 根据Example条件进行查询
     * 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
     * 接口：SelectByExampleMapper<T>
     * @param example 查询示例
     * @return List<T>
     */
    @Override
    public List<T> selectByExample(Object example) {
        return myMapper.selectByExample(example);
    }

    /**
     * 根据指定字段查询
     * @param fieldName 字段名
     * @param fieldValue 字段值
     * @return List<T>
     */
    @Override
    public List<T> selectByField(String fieldName, Object fieldValue) {
        Class<T> tClass = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        T example = null;
        try {
            example = tClass.newInstance();
            BeanUtils.setProperty(example, fieldName, fieldValue);
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return myMapper.select(example);
    }

    /**
     * 根据Example条件进行查询总数
     * 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
     * 接口：SelectCountByExampleMapper<T>
     * @param example 查询示例
     * @return 受影响的行数
     */
    @Override
    public int selectCountByExample(Object example) {
        return myMapper.selectCountByExample(example);
    }

    /**
     * 根据Example条件更新实体record包含的全部属性，null值会被更新
     * 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
     * 接口：UpdateByExampleMapper<T>
     * @param record 数据记录
     * @param example 查询示例
     * @return 受影响的行数
     */
    @Override
    public int updateByExample(T record, Object example) {
        return myMapper.updateByExample(record, example);
    }

    /**
     * 根据Example条件更新实体record包含的不是null的属性值
     * 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
     * 接口：UpdateByExampleSelectiveMapper<T>
     * @param record 数据记录
     * @param example 查询示例
     * @return 受影响的行数
     */
    @Override
    public int updateByExampleSelective(T record, Object example) {
        return myMapper.updateByExampleSelective(record, example);
    }

    /**
     * 根据Example条件删除数据
     * 这个查询支持通过Example类指定查询列，通过selectProperties方法指定查询列
     * 接口：DeleteByExampleMapper<T>
     * @param example 查询示例
     * @return 受影响的行数
     */
    @Override
    public int deleteByExample(Object example) {
        return myMapper.deleteByExample(example);
    }

    /**
     * 根据Condition条件进行查询
     * 接口：SelectByConditionMapper<T>
     * @param condition 查询条件
     * @return List<T>
     */
    @Override
    public List<T> selectByCondition(Object condition) {
        return myMapper.selectByCondition(condition);
    }

    /**
     * 根据Condition条件进行查询总数
     * 接口：SelectCountByConditionMapper<T>
     * @param condition 查询条件
     * @return 受影响的行数
     */
    @Override
    public int selectCountByCondition(Object condition) {
        return myMapper.selectCountByCondition(condition);
    }

    /**
     * 根据Condition条件更新实体record包含的全部属性，null值会被更新
     * 接口：UpdateByConditionMapper<T>
     * @param record 数据记录
     * @param condition 查询条件
     * @return 受影响的行数
     */
    @Override
    public int updateByCondition(T record, Object condition) {
        return myMapper.updateByCondition(record, condition);
    }

    /**
     * 根据Condition条件更新实体record包含的不是null的属性值
     * 接口：UpdateByConditionSelectiveMapper<T>
     * @param record 数据记录
     * @param condition 查询条件
     * @return 受影响的行数
     */
    @Override
    public int updateByConditionSelective(T record, Object condition) {
        return myMapper.updateByConditionSelective(record, condition);
    }

    /**
     * 根据Condition条件删除数据
     * 接口：DeleteByConditionMapper<T>
     * @param condition 查询条件
     * @return 受影响的行数
     */
    @Override
    public int deleteByCondition(Object condition) {
        return myMapper.deleteByCondition(condition);
    }

    /**
     * 根据实体属性和RowBounds进行分页查询
     * 接口：SelectRowBoundsMapper<T>
     * @param record 数据记录
     * @param rowBounds 分页行界
     * @return List<T>
     */
    @Override
    public List<T> selectByRowBounds(T record, RowBounds rowBounds) {
        return myMapper.selectByRowBounds(record, rowBounds);
    }

    /**
     * 根据example条件和RowBounds进行分页查询
     * 接口：SelectByExampleRowBoundsMapper<T>
     * @param example 查询示例
     * @param rowBounds 分页行界
     * @return List<T>
     */
    @Override
    public List<T> selectByExampleAndRowBounds(Object example, RowBounds rowBounds) {
        return myMapper.selectByExampleAndRowBounds(example, rowBounds);
    }

    /**
     * 根据example条件和RowBounds进行分页查询，该方法和selectByExampleAndRowBounds完全一样，只是名字改成了Condition
     * 接口：SelectByConditionRowBoundsMapper<T>
     * @param condition 查询条件
     * @param rowBounds 分页行界
     * @return List<T>
     */
    @Override
    public List<T> selectByConditionAndRowBounds(Object condition, RowBounds rowBounds) {
        return myMapper.selectByExampleAndRowBounds(condition, rowBounds);
    }

    /**
     * 批量插入，支持批量插入的数据库可以使用，例如MySQL,H2等，另外该接口限制实体包含id属性并且必须为自增列
     * 接口：InsertListMapper<T>
     * @param recordList 记录集合
     * @return 受影响的行数
     */
    @Override
    public int insertList(List<T> recordList) {
        return myMapper.insertList(recordList);
    }

    /**
     * 插入数据，限制为实体包含id属性并且必须为自增列，实体配置的主键策略无效
     * 接口：InsertUseGeneratedKeysMapper<T>
     * @param record 数据记录
     * @return 受影响的行数
     */
    @Override
    public int insertUseGeneratedKeys(T record) {
        return myMapper.insertUseGeneratedKeys(record);
    }

    /**
     * 根据主键字符串进行查询，类中只允许存在一个带有@Id注解的字段，否则会抛出异常。
     * 接口：SelectByIdsMapper
     * @param ids 通过操作ids字符串进行操作，ids 如 "1,2,3" 这种形式的字符串
     * @return List<T>
     */
    @Override
    public List<T> selectByIds(String ids) {
        return myMapper.selectByIds(ids);
    }

    /**
     * 根据主键字符串进行删除，类中只允许存在一个带有@Id注解的字段，否则会抛出异常。
     * 接口：DeleteByIdsMapper
     * @param ids 通过操作ids字符串进行操作，ids 如 "1,2,3" 这种形式的字符串
     * @return 受影响的行数
     */
    @Override
    public int deleteByIds(String ids) {
        return myMapper.deleteByIds(ids);
    }

    /**
     * 单表分页查询
     * @param pageNum 当前页码
     * @param pageSize 分页大小
     * @return List<T>
     */
    @Override
    public List<T> pageList(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        //Spring4支持泛型注入
        return myMapper.selectAll();
    }

    /**
     * 验证数据是否存在
     * 接口：SelectByExampleMapper<T>
     * @param example 查询示例
     * @return boolean
     */
    @Override
    public boolean existByExample(Object example) {
        List<T> list = myMapper.selectByExample(example);
        if (list.size() > 0)
            return true;
        return false;
    }

    /*#########################################################################*/
    /*                           自定义扩展接口                                */
    /*#########################################################################*/

    /**
     * 查询某个字段值是否存在
     * @param record 查询实体条件
     * @return boolean
     */
    @Override
    public boolean exist(T record) {
        if (myMapper.exists(record) > 0)
            return true;
        return false;
    }

}
